home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / musik / MIDIFP21 / SOURCES / MIDI_PRT / DRAWER / DRAWER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  20.6 KB  |  650 lines

  1. /**************************************************************
  2. *
  3. *                DRAWER.C
  4. *
  5. **************************************************************/
  6.  
  7. #include <acs.h>
  8. #include <acsplus.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <messages.pif>
  12. #include <acs_plus.pif>
  13. #include <graphics.pif>
  14. #include <notimtab.pif>
  15. #include "..\filter\filter.pif"
  16. #include "..\params\params.pif"
  17. #include "..\info\info.pif"
  18.  
  19. #include "drawer.pif"
  20. #include "drawer.h"
  21. #include "drawer.ah"
  22.  
  23. #define MAX_NOTE_HEIGHT 127
  24.  
  25. #define HEADLINE_DIVIDER 3 /* headl.height = syst.dist./HEADLINE_DIVIDER */
  26. #define INDEX_CHARACTERS 2 /* max. number of characters for index */
  27.  
  28.  
  29. /************* OBJECT DATA PROTOTYPE BEGIN ***********************/
  30.  
  31.  
  32. #define HEADLINE_HEIGHT 12   /* [points] */
  33. #define INDEX_HEIGHT     8   /* [points] */
  34. #define TRACK_HEIGHT     8   /* [points] */
  35.  
  36. /*** possible values for page type ***/
  37.  
  38. #define NO         0x00  /* no valid type */
  39. #define MULTIPLE   0x01  /* one or more whole note systems fit onto this page */
  40. #define PRECEEDING 0x02  /* the tail of the system is on a succeeding page */
  41. #define SUCCEEDING 0x04  /* the head of the system is on a preceeding page */
  42.  
  43. typedef struct 
  44. {
  45.     char number_of_systems ;           /* on this page */
  46.     char type ;                        /* see above */
  47.     int first_track, last_track ;      /* to be drawn for this page */
  48.     TIME min_time ;                    /* in ticks */
  49. PAGE_DESCRIPTOR ;
  50.  
  51. #define MAX_PAGES   200
  52.  
  53. typedef struct 
  54. {
  55. /*** init only data ***/
  56.  
  57.     int handle ;               /* of VDI workstation */
  58.     Awindow *obj_wi ;          /* window of GEM-object to be drawn */
  59.     int obj ;                  /* index of GEM-object to be drawn */
  60.     int width, height ;        /* of GEM-object */
  61.     Awindow *params_wi,        /* related object instances */
  62.             *filter_wi,        /* for access to their hidden data */
  63.             *info_wi ;     
  64.     int ntrks ;                /* number of tracks to be treated */
  65.  
  66. /*** read/write data ***/
  67.  
  68.     int font_id ;
  69.     int current_page ;                 /* number of page that shall be displayed */
  70.     int npgs ;                         /* number of pages with valid layout */
  71.     PAGE_DESCRIPTOR page[MAX_PAGES] ;  /* drawing layout for all pages */
  72.     int x_min, x_max, y_min, y_max ;   /* maximum area allowed for whole drawing */
  73.     int x_min_systems, x_max_systems,  /* same for drawing note systems */
  74.         y_min_systems, y_max_systems ;
  75.     float dy_system, dy_track ; 
  76.     float dy_note, dy_line ;            /* y-distances */
  77.     float dx_bars ;                     /* x-distance */
  78.     float beats_per_system ;            /* quarter beats */
  79.     int bars_per_system ;
  80.     char bar_divider ;
  81.     TIME time_per_system ;              /* in ticks per system */
  82. DRAWER ;
  83.  
  84. /************* OBJECT DATA PROTOTYPE END *************************/
  85.  
  86.  
  87. /*******************************************************************
  88. */
  89.     static void keys(Awindow *wi, int kstate, int key)
  90.     
  91. /* Keyboard procedure of the drawer window. See ACS manual.
  92. *
  93. *******************************************************************/
  94. {
  95.     /*** delayed update ***/
  96.     if (set_timer(wi) == -1) Awi_sendall(REDRAW, wi) ;
  97.     
  98.     /*** inform other windows about key pressure ***/
  99.     key_message.sender = wi ;
  100.     key_message.kstate = kstate ;
  101.     key_message.key    = key ;
  102.     Awi_sendall(KEY_PRESS, &key_message) ;
  103.     
  104.     /*** forward event to ACS for further treatment (e.g. by the desktop) ***/
  105.     Awi_keys(wi, kstate, key) ;
  106. }
  107.  
  108. /*******************************************************************
  109. */
  110.     static int service(Awindow *wi, int task, void *not_used)
  111.     
  112. /* Service routine for messages sent to this window. See ACS manual.
  113. * OUTPUT:  AS_TERM ==> message is forwarded to parent
  114. *          AS_INFO ==> a little help function 
  115. * RETURN:  TRUE:        if task could be treated
  116. *          FALSE:       else
  117. *******************************************************************/
  118. {
  119.     switch (task)
  120.     {    
  121.         case AS_TERM: Awi_sendall(TERMINATE, wi) ; break ; 
  122.         case AS_INFO: A_dialog(&DRAWER_INFO) ; break ;
  123.         default:      return FALSE ;
  124.     }
  125.     return TRUE ;
  126. }
  127.  
  128. /************/
  129. void expand /*
  130. *************/
  131. (
  132.     char lines_per_12,            /* IN: so many horizontal lines are used per 12 notes */
  133.     NOTE min_note,                 /* IN: marks the minimum of the range to be expanded */
  134.     NOTE max_note,                 /* IN: marks the maximum of the range to be expanded */
  135.     NOTE *note_of_first_line ,    /* OUT: first note of the expanded range */
  136.     char *number_of_lines,         /* OUT: the expanded range consists of n*(*number_of_lines) notes */
  137.     char *first_modulo_0        /* OUT: indicates the first line with note mod m == 0 */
  138. )
  139. {
  140.     char notes_per_line = 12 / lines_per_12 ;
  141.     *note_of_first_line = min_note / notes_per_line * notes_per_line ;
  142.  
  143.     *number_of_lines = (max_note - *note_of_first_line + notes_per_line - 1) / 
  144.                         notes_per_line + 1 ; 
  145.     *first_modulo_0 = (lines_per_12 - *note_of_first_line % 12 / notes_per_line) %
  146.                         lines_per_12 ;
  147. }
  148.  
  149. /*************************/
  150. static void button(void) /*
  151. **************************/
  152. {
  153.     switch (ev_obnr) 
  154.     {
  155.     case FIRST:    select_page(ev_window, first) ; break ;
  156.     case PREVIOUS: select_page(ev_window, previous) ; break ;
  157.     case NEXT:     select_page(ev_window, next) ; break ;
  158.     case LAST:     select_page(ev_window, last) ; break ;
  159.     case ZOOM_IN:  Awi_sendall(ZOOM_PLUS, ev_window) ; break ;
  160.     case ZOOM_OUT: Awi_sendall(ZOOM_MINUS, ev_window) ; break ;
  161.     }
  162. }
  163.  
  164. /*******************************************************************
  165. *
  166. *             PUBLISHED INTERFACE
  167. *
  168. *******************************************************************/
  169.  
  170.  
  171. void select_page(Awindow *wi, SELECT_MODE sm) 
  172. {
  173. DRAWER *d = wi->user ;
  174. char *text ;
  175.  
  176.     /*** determine page to be drawn ***/
  177.     if (sm == first) d->current_page = 0 ;
  178.     if (sm == previous)
  179.     {
  180.         if (d->current_page > 0) d->current_page -- ;
  181.         else 
  182.         {
  183.             alert_str(FIRST_PAGE, "") ;
  184.             return ;
  185.         }
  186.     }
  187.     if (sm == next)
  188.     {    
  189.         if (d->current_page < d->npgs - 1) d->current_page ++ ;
  190.         else 
  191.         {
  192.             alert_str(LAST_PAGE, "") ;
  193.             return ;
  194.         }
  195.     }
  196.     if (sm == last) d->current_page = d->npgs - 1 ;
  197.     if (d->current_page > d->npgs - 1) d->current_page = d->npgs - 1 ;
  198.  
  199.     /*** refresh page number in the GEM-object ***/
  200.     text = wi->work[PAGE].ob_spec.tedinfo->te_ptext ;
  201.     if (d->current_page < 100) 
  202.     { 
  203.         text[0] = '0' ; 
  204.         text++ ;
  205.     }
  206.     if (d->current_page < 10) 
  207.     {
  208.         text[0] = '0' ; 
  209.         text++ ;
  210.     }
  211.     itoa( d->current_page, text, 10) ;
  212.     Awi_obchange(wi, PAGE, -1) ;
  213.  
  214.     /*** draw with new parameters ***/ 
  215.     if (sm != same) redraw(wi) ; 
  216. }
  217.  
  218.  
  219. int get_first_page(Awindow *wi)
  220. { return 0 ; }
  221.  
  222.  
  223. int get_last_page(Awindow *wi)
  224. { return ((DRAWER *)wi->user)->npgs - 1 ; }
  225.  
  226.  
  227. static int DRAWER_init(Awindow *wi)
  228.     select_page(wi, same) ; 
  229.     return OK ;
  230. }
  231.  
  232. int get_current_page(Awindow *wi)
  233. DRAWER *d = wi->user ;
  234.  
  235.     d->current_page = atoi(wi->work[PAGE].ob_spec.tedinfo->te_ptext) ;
  236.     if (d->current_page > d->npgs - 1) d->current_page = d->npgs - 1 ;
  237.     wi->state |= AWS_LATEUPDATE ;    /* call DRAWER_init() later */
  238.     return d->current_page ;
  239. }
  240.  
  241.  
  242. void redraw(Awindow *wi)
  243. {
  244. DRAWER *d = wi->user ;
  245.  
  246.     /*** layout all pages ***/
  247.     if ( page_layouter(d->handle, d->width, d->height, wi) == LAYOUT_ERR )
  248.         return ;
  249.     /*** refresh target object ***/
  250.     Awi_obchange(d->obj_wi, d->obj, (d->obj_wi)->work[d->obj].ob_state) ;
  251. }
  252.  
  253.  
  254. void draw_page(int handle, Awindow *wi, int x0, int y0, int *points, 
  255.                int zoom, int page)
  256. {
  257. DRAWER *d = wi->user ;
  258. PAGE_DESCRIPTOR *p = &d->page[page] ;
  259. TIME min_time, max_time ;
  260. NOTE min_note, max_note, note_of_y ;
  261. char *track_name, *text = "----" ;
  262. float y_min, y_max ;
  263. int system, track ;
  264. char number_of_lines, first_shadow ;
  265. int index_width, dummy ;
  266. int style[12], color[12], type, height, dynamic, mode ;
  267. MARK_MODE back_mode ;
  268. int hor_lines, back_style[12], back_color[12], 
  269.     black[12] = { 1,1,1,1,1,1,1,1,1,1,1,1 }, dots ;
  270. float dyn_scale ;
  271.  
  272.     if (d->npgs == 0) return ;
  273.     vst_font(handle, d->font_id) ;
  274.  
  275.     /*** draw title and page number ***/
  276.     if (y0 + d->y_min_systems * zoom > points[1])
  277.     {
  278.         vst_height(handle, (d->dy_system * zoom)/HEADLINE_DIVIDER, 
  279.                    &dummy, &dummy, &dummy, &dummy) ;
  280.         vst_alignment(handle, 1, 2, &dummy, &dummy) ;
  281.         vst_effects(handle, get_text_effects(d->params_wi)) ;
  282.         v_gtext(handle, 
  283.                 x0 + ((d->x_min + d->x_max)>>1) * zoom, 
  284.                 y0 + d->y_min * zoom, 
  285.                 get_title(d->params_wi)) ;
  286.         vst_alignment(handle, 2, 2, &dummy, &dummy) ;
  287.         vst_effects(handle, NORMAL) ;
  288.         v_gtext(handle, x0 + d->x_max * zoom, y0 + d->y_min * zoom, 
  289.                 itoa(page, text, 10)) ;
  290.     }
  291.     /*** fetch note parameters and normalize ***/
  292.     get_style_params(d->params_wi, 
  293.                      style, color, &type, &height, &dynamic,
  294.                      back_style, back_color) ;
  295.     hor_lines = get_hor_lines(d->params_wi) ;
  296.     mode = get_mode(d->params_wi) ;
  297.     height = ( d->dy_note * (height + 1) )/5 ;
  298.     dyn_scale = ( (float)dynamic ) / 10 ;
  299.  
  300.     /*** draw note system(s) ***/        
  301.     y_min = y_max = d->y_min_systems ;
  302.     if (p->type & SUCCEEDING) y_max += d->dy_track ;
  303.     for (system = 0 ; system < p->number_of_systems ; system ++)
  304.     {
  305.         min_time = p->min_time + system * d->time_per_system ;
  306.         max_time = min_time + d->time_per_system ;
  307.         for (track = p->first_track ; track <= p->last_track ; track++)
  308.         {
  309.             if ( get_min_max(d->filter_wi, track, min_time, max_time,
  310.                              &min_note, &max_note) )
  311.             {
  312.                 expand(hor_lines, min_note, max_note, 
  313.                          ¬e_of_y, &number_of_lines, &first_shadow) ;
  314.                 if (note_of_y > MAX_NOTE_HEIGHT) note_of_y = 1 ;
  315.                 y_max += d->dy_line * (number_of_lines - 1) ;
  316.                 
  317.                 /*** if track is visible (inside clipping area) ***/
  318.                 if ( ((y_max + d->dy_line) * zoom + y0 > points[1]) && 
  319.                      ((y_max - d->dy_line * (number_of_lines + 1)) * zoom + y0 < points[3]) )
  320.                 {
  321.                     /*** draw horizontal lines with index and shadow ***/
  322.                     vsl_type(handle, SOLID) ; 
  323.                     vst_height(handle, 4 * zoom * d->dy_note, &index_width, &dummy, &dummy, &dummy) ;
  324.                     vst_alignment(handle, 2, 0, &dummy, &dummy) ;
  325.                     vsf_interior(handle, FIS_PATTERN) ;
  326.                     vsf_perimeter(handle, 0) ; /* no perimeter */
  327.                     dots = -1 /* no dots */ ; back_mode = behind ;
  328.                     if (mode == Rieder) back_mode = between ;
  329.                     else if (mode == Beyreuther)
  330.                         dots = d->bars_per_system * (d->bar_divider - 1) ;
  331.                     draw_lines(handle, number_of_lines, first_shadow, hor_lines,
  332.                                back_mode, back_style, back_color, (note_of_y + 11)/12, dots,
  333.                                - index_width, 0,
  334.                                x0 + d->x_min_systems * zoom, y0 + y_max * zoom, 
  335.                                x0 + d->x_max_systems * zoom, y0 + y_max * zoom,
  336.                                0, - d->dy_line * zoom) ;
  337.                     /*** draw track name ***/
  338.                     track_name = get_track_name(d->filter_wi, track) ;
  339.                     vst_alignment(handle, 0, 3, &dummy, &dummy) ;
  340.                     vswr_mode(handle, MD_TRANS) ;
  341.                     v_gtext(handle, x0 + d->x_min_systems * zoom, 
  342.                             y0 + (y_max - (d->dy_line * (number_of_lines - 1) 
  343.                                   + d->dy_note * 2)) * zoom, track_name ) ;
  344.                     vswr_mode(handle, MD_REPLACE) ;
  345.                     /*** draw notes of the current track ***/
  346.                     vsl_color(handle, BLACK) ;
  347.                     vsf_perimeter(handle, 1) ; /* with perimeter */
  348.                     draw_track(handle, d->filter_wi, track,
  349.                                x0 + d->x_min_systems * zoom, 
  350.                                x0 + d->x_max_systems * zoom, 
  351.                                y0 + y_max * zoom, - d->dy_note * zoom,
  352.                                min_time, max_time, 
  353.                                note_of_y, height * zoom, dyn_scale, 
  354.                                type, style, color) ;
  355.                 }
  356.                 y_max += d->dy_track ;
  357.             }
  358.         }
  359.         if ( (system != p->number_of_systems - 1) || !(p->type & PRECEEDING) ) 
  360.             y_max -= d->dy_track ;
  361.         if (mode != Beyreuther)
  362.         {
  363.             /*** draw dashed horizontal lines (sub-bars) ***/
  364.             vsl_udsty(handle, 0x2222) ;
  365.             vsl_type(handle, USERLINE) ;
  366.             draw_lines(handle, (d->bars_per_system * d->bar_divider) + 1, -1, -1,
  367.                        back_mode, back_style, black, 0, -1, 0, 0,
  368.                        x0 + d->x_min_systems * zoom, y0 + y_min * zoom + 1, 
  369.                        x0 + d->x_min_systems * zoom, y0 + y_max * zoom - 1,
  370.                        d->dx_bars/d->bar_divider * zoom, 0) ;
  371.         }
  372.         /*** draw solid vertical lines (bars) ***/
  373.         vsl_type(handle, SOLID) ; 
  374.         draw_lines(handle, d->bars_per_system + 1, -1, -1,
  375.                    back_mode, back_style, black, 0, -1, 0, 0,
  376.                    x0 + d->x_min_systems * zoom, y0 + y_min * zoom + 1, 
  377.                    x0 + d->x_min_systems * zoom, y0 + y_max * zoom - 1,
  378.                    d->dx_bars * zoom, 0) ;
  379.         /*** draw bar number ***/
  380.         vswr_mode(handle, MD_TRANS) ;
  381.         vst_alignment(handle, 2, 3, &dummy, &dummy) ;
  382.         v_gtext(handle, x0 + d->x_max_systems * zoom, 
  383.                 y0 + (y_min - d->dy_note) * zoom, 
  384.                 itoa(max_time/d->time_per_system * d->bars_per_system, text, 10)) ;
  385.         vswr_mode(handle, MD_REPLACE) ;
  386.         y_max += d->dy_system ; y_min = y_max ;
  387.     }
  388. }
  389.  
  390.  
  391. int page_layouter(int handle, int width, int height, Awindow *wi)
  392. {
  393. DRAWER *d = wi->user ;
  394. int index_width, index_height, headline_width, headline_height ; 
  395. char number_of_lines, first_modulo_0 ;
  396. int first_active_track, last_active_track ;
  397. PAGE_DESCRIPTOR *page ;   
  398. int p ;                   /* page number */
  399. int t ;                   /* track number */
  400. float y ;                 /* current y value */
  401. NOTE min_note, max_note, note_of_y ;
  402. TIME time, max_time ;
  403. int dummy, hor_lines ;
  404.  
  405.     /*** get maximum area allowed for whole drawing ***/
  406.     d->x_min = ((long)(width - 1)) * 
  407.                       get_left_border(d->params_wi) / 100 ;
  408.     d->x_max = ((long)(width - 1)) * 
  409.                       (100 - get_right_border(d->params_wi)) / 100 ;
  410.     d->y_min = ((long)(height - 1)) * 
  411.                       get_upper_border(d->params_wi) / 100 ;
  412.     d->y_max = ((long)(height - 1)) * 
  413.                       (100 - get_lower_border(d->params_wi)) / 100 ;
  414.  
  415.     /*** check for plausability ***/
  416.     if ( (d->x_min >= d->x_max) || (d->y_min >= d->y_max) )
  417.     {
  418.         alert_str(INVALID_BORDER_VALUES, "") ;
  419.         d->npgs = 0 ;
  420.         return LAYOUT_ERR ; 
  421.     }
  422.  
  423.     /*** times, bars ***/
  424.     d->beats_per_system = ((float)get_system_length(d->params_wi))/2 ;
  425.     d->time_per_system = d->beats_per_system * 
  426.                          get_ticks_per_beat(d->info_wi) ;
  427.     d->bars_per_system = get_bars_per_system(d->params_wi) ;
  428.     d->bar_divider = get_bar_divider(d->params_wi) ;
  429.  
  430.     /*** get y-distances ***/
  431.     d->dy_system = ((float)height * get_system_distance(d->params_wi)) / 100 ;
  432.     d->dy_track = ((float)height * get_track_distance(d->params_wi)) / 100 ;
  433.     d->dy_note = ((float)height * get_note_distance(d->params_wi)) / 1000 ;
  434.     hor_lines = get_hor_lines(d->params_wi) ;
  435.     switch (hor_lines)
  436.     {
  437.     case 1: d->dy_line = d->dy_note * 12 ; break ;
  438.     case 2: d->dy_line = d->dy_note * 6 ; break ;
  439.     case 3: d->dy_line = d->dy_note * 4 ; break ;
  440.     case 4:
  441.     case 5: d->dy_line = d->dy_note * 3 ; break ;
  442.     default: d->dy_line = d->dy_note * 2 ;
  443.     }
  444.  
  445.     /*** get font and its attributes ***/
  446.     d->font_id = get_font_id(d->params_wi) ;
  447.     if ( d->font_id != vst_font(handle, d->font_id) )
  448.     {
  449.         alert_str(FONT_NOT_EXISTING, "") ;
  450.         d->npgs = 0 ;
  451.         return LAYOUT_ERR ; 
  452.     } 
  453.     /*** note: actual index_height needs not to be desired height ***/
  454.     vst_height(handle, 4 * d->dy_note, 
  455.                &index_width, &index_height, &dummy, &dummy) ;
  456.     /*** note: actual headline_height needs not to be HEADLINE_HEIGHT ! ***/
  457.     vst_height(handle, d->dy_system/HEADLINE_DIVIDER, 
  458.               &headline_width, &headline_height, &dummy, &dummy) ;
  459.     
  460.     /*** get maximum area allowed for drawing note systems ***/
  461.     d->x_min_systems = d->x_min + INDEX_CHARACTERS * index_width ;
  462.     d->x_max_systems = d->x_max ;
  463.     d->y_min_systems = d->y_min + d->dy_system + headline_height/2 ;
  464.     d->y_max_systems = d->y_max ;
  465.  
  466.     /*** get x-distances ***/
  467.     d->dx_bars = ((float)(d->x_max_systems - d->x_min_systems)) /
  468.                   d->bars_per_system ;
  469.  
  470.     /*** tracks ***/
  471.     first_active_track = get_first_active_track(d->filter_wi) ;
  472.     last_active_track = get_last_active_track(d->filter_wi) ;
  473.     if ( (first_active_track < 0) || (last_active_track < 0) )
  474.     {
  475.         alert_str(ALL_TRACKS_OFF, "") ;
  476.         d->npgs = 0 ;
  477.         return LAYOUT_ERR ;
  478.     }
  479.  
  480.     /*** layout all pages ***/
  481.     p = 0 ; d->npgs = 1 ; 
  482.     page = d->page ;
  483.     page[p].min_time = 0 ;
  484.     page[p].type = NONE ;
  485.     page[p].number_of_systems = 0 ;
  486.     page[p].first_track = first_active_track ; 
  487.     t = first_active_track ;
  488.     y = d->y_min_systems ;
  489.     time = 0 ;
  490.     max_time = get_absolute_max_time(d->filter_wi) ;
  491.  
  492.     while ( (time < max_time) && (p < MAX_PAGES - 1) ) 
  493.     {
  494.         /*** layout one system ***/
  495.         while ( (t <= last_active_track) && 
  496.                 (time < max_time) && (p < MAX_PAGES - 1) )
  497.         {
  498.             if (page[p].type & SUCCEEDING) y += d->dy_track ;
  499.             while ( (y <= d->y_max_systems) && (t <= last_active_track) )
  500.             {
  501.                 /*** if this track is active ***/
  502.                 if (get_min_max(d->filter_wi, t, 
  503.                                 time, time + d->time_per_system,
  504.                                 &min_note, &max_note))
  505.                 {
  506.                     expand(hor_lines, min_note, max_note, 
  507.                              ¬e_of_y, &number_of_lines, &first_modulo_0) ;
  508.                     /*** fits each track into the allowed y-range of a page ? ***/
  509.                     if (d->dy_line * (number_of_lines - 1) > 
  510.                     d->y_max_systems - d->y_min_systems - 2 * d->dy_track)
  511.                     {
  512.                         alert_str(TRACK_TOO_HIGH, "") ;
  513.                         d->npgs = p ;    
  514.                         return LAYOUT_ERR ;
  515.                     }
  516.                     y += d->dy_line * (number_of_lines - 1) ;
  517.                     y += d->dy_track ;
  518.                 }
  519.                 t ++ ;
  520.             }
  521.             t -- ;
  522.             if (y > d->y_max_systems)
  523.             {
  524.                 /*** the current note system does not fit onto this page ***/
  525.                 if (page[p].number_of_systems == 0)
  526.                 {
  527.                     /*** this is the first system for this page ***/
  528.                     page[p].type |= PRECEEDING ; 
  529.                     page[p].last_track = t - 1 ; 
  530.                     page[p].number_of_systems = 1 ; /* but not a whole system */
  531.                     y = d->y_min_systems ;
  532.                     p ++ ; d->npgs ++ ;
  533.                     page[p].type = SUCCEEDING ;
  534.                     page[p].first_track = t ;
  535.                     page[p].number_of_systems = 0 ;
  536.                 }
  537.                 else 
  538.                 {
  539.                     /*** there are already one or more systems on this page ***/
  540.                     y = d->y_min_systems ;
  541.                     p ++ ; d->npgs ++ ;
  542.                     page[p].type = NONE ;
  543.                     t = page[p].first_track = first_active_track ;
  544.                     page[p].number_of_systems = 0 ;
  545.                 }
  546.                 page[p].min_time = time ;
  547.             }
  548.             else
  549.             {
  550.                 /*** the current note system fits onto this page ***/
  551.                 time += d->time_per_system ;
  552.                 t = first_active_track ;
  553.                 if (page[p].type == SUCCEEDING)
  554.                 {
  555.                     /*** one and only system for this page, take a new page ***/
  556.                     page[p].last_track = last_active_track ; 
  557.                     page[p].number_of_systems = 1 ; /* but not a whole system */
  558.                     y = d->y_min_systems ;
  559.                     p ++ ; if (time < max_time) d->npgs ++ ;
  560.                     page[p].type = NONE ;
  561.                     page[p].first_track = first_active_track ;
  562.                     page[p].last_track = first_active_track ;
  563.                     page[p].number_of_systems = 0 ;
  564.                     page[p].min_time = time ;
  565.                 }
  566.                 else
  567.                 {
  568.                     /*** one more system for this page ***/
  569.                     page[p].type = MULTIPLE ;
  570.                     page[p].last_track = last_active_track ;
  571.                     page[p].number_of_systems ++ ;
  572.                     y += (d->dy_system - d->dy_track) ;
  573.                     page[p+1].type = NONE ;
  574.                     page[p+1].first_track = first_active_track ;
  575.                 }
  576.             }
  577.         }
  578.     }
  579.     if (d->current_page > d->npgs - 1) d->current_page = d->npgs - 1 ;
  580.     if (d->npgs >= MAX_PAGES - 1)
  581.     {
  582.         alert_str(MAX_PAGES_REACHED, "" ) ;
  583.     }
  584.     return LAYOUT_GOOD ;
  585. }
  586.  
  587.  
  588. void reset_layout(Awindow *wi)
  589.     DRAWER *d = wi->user ;
  590.     page_layouter(d->handle, d->width, d->height, wi) ;
  591. }
  592.                     
  593.         
  594. void DRAWER_destructor(Awindow *wi)
  595. {
  596.     if (wi) 
  597.     {
  598.         memory_symptom = "DrDstr wi->user" ;
  599.         if (wi->user) My_free(wi->user) ;
  600.         memory_symptom = "DrDstr wi" ;
  601.         Awi_delete(wi) ;
  602.     }
  603. }
  604.  
  605.  
  606. Awindow *DRAWER_constructor(DRAWER_INIT *drawer_init)
  607. {
  608. Awindow *wi ;
  609. DRAWER *d ;
  610.  
  611.     /*** enter filename into icon text and info line ***/
  612.     DRAWER_WINDOW.iconblk = drawer_init->icon ;
  613.     DRAWER_WINDOW.iconblk->monoblk.ib_ptext = drawer_init->filename ;
  614.     DRAWER_WINDOW.info = drawer_init->filename ;
  615.  
  616.     /*** create the DRAWER window ***/
  617.     wi = Awi_create(&DRAWER_WINDOW) ;
  618.     if (!wi) return NULL ;
  619.  
  620.     /*** allocate drawer structure and initialize ***/
  621.     wi->user = d = My_alloc(sizeof *d) ;
  622.     if (!d) { DRAWER_destructor(wi) ; return NULL ;    }
  623.     d->handle = drawer_init->handle ;
  624.     d->obj_wi = drawer_init->obj_wi ;
  625.     d->obj = drawer_init->obj ;
  626.     d->width = drawer_init->width ;
  627.     d->height = drawer_init->height ;
  628.     d->params_wi = drawer_init->params_window ;
  629.     d->filter_wi = drawer_init->filter_window ;
  630.     d->info_wi = drawer_init->info_window ;
  631.     d->ntrks = get_number_of_tracks(drawer_init->info_window) ;
  632.     d->current_page = 0 ; 
  633.     d->npgs = 0 ;
  634.  
  635.     /*** draw at once ***/
  636.     redraw(wi) ; 
  637.  
  638.     /*** return success message ***/
  639.     return wi ;
  640. }
  641.  
  642.